(2024/04/06更新) 因應React在18後更新了許多不同的語法,更新後的教學之後將陸續放在 新的blog 中,歡迎讀者到該處閱讀,我依然會回覆這邊的提問
不對啊,幹嘛不用jQuery的ajax?
簡單來說,因為jQuery運作模式/渲染DOM的方式和React不太一樣,為避免發生衝突,一般不會希望在React中使用jQuery,而是用其他native或專為React設計的方式來取代。所以這邊要介紹的,就是取代jQuery的Ajax的其中一個方法: Fetch Api。
2019/09/27
補充一下精確的說法: 如果只用 jQuery的ajax的話是沒關係的,只是我們不會為了ajax特別去載jQuery那一包。
(參考後設鐵人 Day22:塗鴉之城之後決定補充一下)
Fetch Api是內建於JavaScript web api的一部份。使用時,不需要額外下載或嵌入CDN。Fetch是一個Promise,我們有在第3篇【React.js入門 - 03】 開始之前應該要知道的DOM和ES6提過Promise的語法,而Fetch的用法是這樣的:
fetch( request的url, { /*設定request內容*/})
.then(res => res.json()) /*把request json化*/
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
url的地方是你request的路徑,接收的是字串型態。因為fetch要先把接到的response json化之後才能拿到response中的data,所以這邊會有兩個.then()
。接下來我們來講常見fetch使用方法:
設定fetch所執行的method,是使用字串。這個範例是使用GET方法:
fetch( request的url, {method: "GET"}) /*設定使用GET*/
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
headers必須要是個Headers物件。在下面的範例我們先用來設定Content-Type
fetch( request的url, {
method: "GET",
headers: new Headers({
'Content-Type': 'application/json',
})
})
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
在認證、會員系統中,後端常常會要求在要求只有該會員才能看到的資料時,由前端在header中傳送在登入時取得的token。在fetch api中要這樣夾帶:
const token = "Bearer "+ 我存好的token ;
fetch( request的url, {
method: "GET",
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': token, /* 把token放在這 */
})
})
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
注意要視你儲存token的方式、token的類型,決定是不是要做前處理,像jwt要在token前面加上"Bearer "
。
另外,token也能透過url以參數方式傳送。方式是url= 原url + '?token=' + 存好的token;
,但一般還是會希望透過header傳token。
用fetch在body傳送 json type的資料時,要把原資料字串化,接收者才會接到json格式的資料。
const data= { A:"資料A", B:"資料B" }
fetch( request的url, {
method: "GET",
body: JSON.stringify(data), /*把json資料字串化*/
headers: new Headers({
'Content-Type': 'application/json'
})
})
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
這個比較麻煩,我們必須要對data做這樣的前處理:
const data= { A:"資料A", B:"資料B" };
const formData = Object.keys(data).map(
function (keyName) {
return encodeURIComponent(keyName) + '=' + encodeURIComponent(data[keyName])
}
).join('&');
其他就和前面差不多,改一下headers的content-type就好
const data= { A:"資料A", B:"資料B" };
const formData = Object.keys(data).map(
function (keyName) {
return encodeURIComponent(keyName) + '=' + encodeURIComponent(data[keyName])
}
).join('&');
fetch( request的url, {
method: "GET",
body: formData, /*使用處理後的資料*/
headers: new Headers({
"Content-type": "application/x-www-form-urlencoded"
})
})
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
})
.catch(e => {
/*發生錯誤時要做的事情*/
})
這個範例中,只要我們按下按鍵,就能取得jserv大神在github中的repository,並顯示以英文字母排序後,第一個repository的名字。
獲取github上特定使用者repo的url是'https://api.github.com/users/使用者名稱/repos'
。它是GET method,response data的格式是這個樣子的:
我們必須觸發fetch後,存取response第0個資料的「name」,才能做到我們要做的事情。
也就是所有的程式碼長這樣:
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state={
repoName: null
}
this.handleClick=this.handleClick.bind(this);
}
handleClick(){
fetch( 'https://api.github.com/users/jserv/repos',{method:"GET"})
.then(res => res.json())
.then(data => {
/*接到request data後要做的事情*/
this.setState({repoName: data[0]['name']});
})
.catch(e => {
/*發生錯誤時要做的事情*/
console.log(e);
})
}
render() {
return (
<div className="App">
<div className="data-display">
{(this.state.repoName===null)?"目前還有沒有資料":this.state.repoName}
</div>
<button onClick={this.handleClick}>取得jserv以英文字母排序的第一個repo</button>
</div>
)
}
};
執行結果:
來看看老師是不是真的有這個repo:
fetch還有許多可以設定的地方,可以翻閱MDN了解細節。
到這邊,你應該知道了fetch的使用方法。搭配button,你也有辦法讓網頁被動讓使用者呼叫fetch。但是有的時候,我們希望載入網頁時就主動用http request去取得資料,這又要怎麼處理呢?
從下一篇,我們會開始講生命週期,到時候就會討論到這個問題。